מדריך מקיף ל-Solid Router, הראוטר הרשמי של SolidJS, המכסה התקנה, שימוש, תכונות מתקדמות ושיטות מומלצות לבניית יישומי עמוד-יחיד חלקים ורציפים.
Solid Router: שליטה בניווט צד-לקוח ב-SolidJS
SolidJS, הידועה בביצועים יוצאי הדופן ובפשטות שלה, מספקת בסיס פנטסטי לבניית יישומי ווב מודרניים. כדי ליצור חוויות מרתקות וידידותיות למשתמש באמת, ראוטר צד-לקוח חזק הוא חיוני. הכירו את Solid Router, הראוטר הרשמי והמומלץ עבור SolidJS, שתוכנן להשתלב באופן חלק עם עקרונות הריאקטיביות של הפריימוורק.
מדריך מקיף זה יעמיק בעולמו של Solid Router, ויכסה הכל החל מהגדרה בסיסית ועד לטכניקות מתקדמות לבניית יישומי עמוד-יחיד (SPAs) מורכבים ודינמיים. בין אם אתם מפתחי SolidJS מנוסים או רק מתחילים, מאמר זה יצייד אתכם בידע ובכישורים הדרושים כדי לשלוט בניווט צד-לקוח.
מהו Solid Router?
Solid Router הוא ראוטר צד-לקוח קל משקל ובעל ביצועים גבוהים, שתוכנן במיוחד עבור SolidJS. הוא ממנף את הריאקטיביות של SolidJS כדי לעדכן ביעילות את ממשק המשתמש בהתבסס על שינויים בכתובת ה-URL של הדפדפן. בניגוד לראוטרים מסורתיים המסתמכים על השוואת DOM וירטואלי (virtual DOM diffing), Solid Router מבצע מניפולציה ישירה על ה-DOM, מה שמוביל לביצועים מהירים וצפויים יותר.
תכונות עיקריות של Solid Router כוללות:
- ניתוב דקלרטיבי: הגדירו את הנתיבים שלכם באמצעות API פשוט ואינטואיטיבי מבוסס JSX.
- ניתוב דינמי: טפלו בקלות בנתיבים עם פרמטרים, מה שמאפשר לכם ליצור יישומים דינמיים מבוססי-נתונים.
- נתיבים מקוננים: ארגנו את היישום שלכם לחלקים לוגיים באמצעות נתיבים מקוננים.
- קומפוננטת קישור: נווטו בצורה חלקה בין נתיבים באמצעות קומפוננטת
<A>, המטפלת אוטומטית בעדכוני URL ובעיצוב קישורים פעילים. - טעינת נתונים: טענו נתונים באופן אסינכרוני לפני רינדור נתיב, כדי להבטיח חווית משתמש חלקה.
- מעברים: צרו מעברים מושכים ויזואלית בין נתיבים כדי לשפר את חווית המשתמש.
- טיפול בשגיאות: טפלו בשגיאות באלגנטיות והציגו דפי שגיאה מותאמים אישית.
- שילוב עם History API: משתלב באופן חלק עם ה-History API של הדפדפן, ומאפשר למשתמשים לנווט באמצעות לחצני 'אחורה' ו'קדימה'.
תחילת עבודה עם Solid Router
התקנה
כדי להתקין את Solid Router, השתמשו במנהל החבילות המועדף עליכם:
npm install @solidjs/router
yarn add @solidjs/router
pnpm add @solidjs/router
הגדרה בסיסית
הליבה של Solid Router סובבת סביב הקומפוננטות <Router> ו-<Route>. קומפוננטת <Router> משמשת כשורש של מערכת הניתוב ביישום שלכם, בעוד שקומפוננטות <Route> מגדירות את המיפוי בין כתובות URL לקומפוננטות.
הנה דוגמה בסיסית:
import { Router, Route } from '@solidjs/router';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<Router>
<Route path="/"> <Home/> </Route>
<Route path="/about"> <About/> </Route>
</Router>
);
}
export default App;
בדוגמה זו, קומפוננטת <Router> עוטפת את כל היישום. קומפוננטות <Route> מגדירות שני נתיבים: אחד עבור נתיב השורש ("/") ואחר עבור הנתיב "/about". כאשר המשתמש ינווט לאחד מהנתיבים הללו, הקומפוננטה המתאימה (Home או About) תרונדר.
קומפוננטת <A>
כדי לנווט בין נתיבים, השתמשו בקומפוננטת <A> שמסופקת על ידי Solid Router. קומפוננטה זו דומה לתגית <a> רגילה ב-HTML, אך היא מטפלת אוטומטית בעדכוני URL ומונעת טעינה מחדש של כל הדף.
import { A } from '@solidjs/router';
function Navigation() {
return (
<nav>
<A href="/">Home</A>
<A href="/about">About</A>
</nav>
);
}
export default Navigation;
כאשר המשתמש ילחץ על אחד מהקישורים הללו, Solid Router יעדכן את כתובת ה-URL בדפדפן ויציג את הקומפוננטה המתאימה מבלי לגרום לטעינה מחדש של כל הדף.
טכניקות ניתוב מתקדמות
ניתוב דינמי עם פרמטרים של נתיב
Solid Router תומך בניתוב דינמי, המאפשר לכם ליצור נתיבים עם פרמטרים. זה שימושי להצגת תוכן המבוסס על מזהה (ID) או slug ספציפי.
import { Router, Route } from '@solidjs/router';
import UserProfile from './components/UserProfile';
function App() {
return (
<Router>
<Route path="/users/:id"> <UserProfile/> </Route>
</Router>
);
}
export default App;
בדוגמה זו, המקטע :id בנתיב הוא פרמטר של נתיב. כדי לגשת לערך של הפרמטר id בתוך קומפוננטת UserProfile, ניתן להשתמש ב-hook שנקרא useParams:
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
function UserProfile() {
const params = useParams();
const [user] = createResource(() => params.id, fetchUser);
return (
<div>
<h1>User Profile</h1>
{user() ? (
<div>
<p>Name: {user().name}</p>
<p>Email: {user().email}</p>
</div>
) : (<p>Loading...</p>)}
</div>
);
}
async function fetchUser(id: string) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}
export default UserProfile;
ה-hook useParams מחזיר אובייקט המכיל את פרמטרי הנתיב. במקרה זה, params.id יכיל את הערך של הפרמטר id מכתובת ה-URL. לאחר מכן, משתמשים ב-hook createResource כדי להביא את נתוני המשתמש על סמך המזהה.
דוגמה בינלאומית: דמיינו פלטפורמת מסחר אלקטרוני גלובלית. ניתן להשתמש בניתוב דינמי כדי להציג פרטי מוצר על בסיס מזהה המוצר: /products/:productId. זה מאפשר ליצור בקלות כתובות URL ייחודיות לכל מוצר, מה שמקל על משתמשים לשתף ולשמור פריטים ספציפיים, ללא קשר למיקומם.
נתיבים מקוננים
נתיבים מקוננים מאפשרים לארגן את היישום לחלקים לוגיים. זה שימושי במיוחד עבור יישומים מורכבים עם רמות ניווט מרובות.
import { Router, Route } from '@solidjs/router';
import Dashboard from './components/Dashboard';
import Profile from './components/Profile';
import Settings from './components/Settings';
function App() {
return (
<Router>
<Route path="/dashboard">
<Dashboard/>
<Route path="/profile"> <Profile/> </Route>
<Route path="/settings"> <Settings/> </Route>
</Route>
</Router>
);
}
export default App;
בדוגמה זו, קומפוננטת <Dashboard> משמשת כקונטיינר עבור הקומפוננטות <Profile> ו-<Settings>. הנתיבים <Profile> ו-<Settings> מקוננים בתוך הנתיב <Dashboard>, מה שאומר שהם יוצגו רק כאשר המשתמש נמצא בנתיב "/dashboard".
כדי לרנדר את הנתיבים המקוננים בתוך קומפוננטת <Dashboard>, עליכם להשתמש בקומפוננטת <Outlet>:
import { Outlet } from '@solidjs/router';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<nav>
<A href="/dashboard/profile">Profile</A>
<A href="/dashboard/settings">Settings</A>
</nav>
<Outlet/>
</div>
);
}
export default Dashboard;
קומפוננטת <Outlet> משמשת כממלא-מקום (placeholder) שבו ירונדרו הנתיבים המקוננים. כאשר המשתמש ינווט ל-"/dashboard/profile", קומפוננטת <Profile> תרונדר בתוך קומפוננטת <Outlet>. באופן דומה, כאשר המשתמש ינווט ל-"/dashboard/settings", קומפוננטת <Settings> תרונדר בתוך קומפוננטת <Outlet>.
טעינת נתונים עם createResource
טעינת נתונים באופן אסינכרוני לפני רינדור נתיב היא חיונית כדי לספק חווית משתמש חלקה. Solid Router משתלב בצורה חלקה עם ה-hook createResource של SolidJS, מה שהופך את טעינת הנתונים למשימה פשוטה.
ראינו דוגמה לכך קודם לכן בקומפוננטת UserProfile, אך הנה היא שוב לשם הבהירות:
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
function UserProfile() {
const params = useParams();
const [user] = createResource(() => params.id, fetchUser);
return (
<div>
<h1>User Profile</h1>
{user() ? (
<div>
<p>Name: {user().name}</p>
<p>Email: {user().email}</p>
</div>
) : (<p>Loading...</p>)}
</div>
);
}
async function fetchUser(id: string) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}
export default UserProfile;
ה-hook createResource מקבל שני ארגומנטים: סיגנל (signal) המפעיל את טעינת הנתונים ופונקציה המביאה את הנתונים. במקרה זה, הסיגנל הוא () => params.id, מה שאומר שהנתונים יובאו בכל פעם שהפרמטר id משתנה. הפונקציה fetchUser מביאה את נתוני המשתמש מ-API על בסיס המזהה.
ה-hook createResource מחזיר מערך המכיל את המשאב (הנתונים שהובאו) ופונקציה להבאת הנתונים מחדש. המשאב הוא סיגנל המחזיק את הנתונים. ניתן לגשת לנתונים על ידי קריאה לסיגנל (user()). אם הנתונים עדיין בטעינה, הסיגנל יחזיר undefined. זה מאפשר לכם להציג חיווי טעינה בזמן שהנתונים נטענים.
מעברים
הוספת מעברים בין נתיבים יכולה לשפר משמעותית את חווית המשתמש. אמנם ל-Solid Router אין תמיכה מובנית במעברים, אך הוא משתלב היטב עם ספריות כמו solid-transition-group כדי להשיג מעברים חלקים ומושכים ויזואלית.
ראשית, התקינו את החבילה solid-transition-group:
npm install solid-transition-group
yarn add solid-transition-group
pnpm add solid-transition-group
לאחר מכן, עטפו את הנתיבים שלכם בקומפוננטת <TransitionGroup>:
import { Router, Route } from '@solidjs/router';
import { TransitionGroup, Transition } from 'solid-transition-group';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<Router>
<TransitionGroup>
<Route path="/">
<Transition name="fade" duration={300}>
<Home/>
</Transition>
</Route>
<Route path="/about">
<Transition name="fade" duration={300}>
<About/>
</Transition>
</Route>
</TransitionGroup>
</Router>
);
}
export default App;
בדוגמה זו, כל נתיב עטוף בקומפוננטת <Transition>. המאפיין name מציין את קידומת קלאס ה-CSS עבור המעבר, והמאפיין duration מציין את משך המעבר באלפיות השנייה.
יהיה עליכם להגדיר את קלאס ה-CSS המתאימים למעבר בקובץ הסגנונות שלכם:
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 300ms ease-in;
}
.fade-exit {
opacity: 1;
}
.fade-exit-active {
opacity: 0;
transition: opacity 300ms ease-out;
}
קוד CSS זה מגדיר מעבר fade-in/fade-out פשוט. כאשר נכנסים לנתיב, מוחלים הקלאסים .fade-enter ו-.fade-enter-active, הגורמים לקומפוננטה להופיע בהדרגה. כאשר יוצאים מנתיב, מוחלים הקלאסים .fade-exit ו-.fade-exit-active, הגורמים לקומפוננטה להיעלם בהדרגה.
טיפול בשגיאות
טיפול אלגנטי בשגיאות הוא חיוני כדי לספק חווית משתמש טובה. ל-Solid Router אין מנגנון מובנה לטיפול בשגיאות, אך ניתן ליישם זאת בקלות באמצעות error boundary גלובלי או מטפל שגיאות ספציפי לנתיב.
הנה דוגמה ל-error boundary גלובלי:
import { createSignal, Suspense, ErrorBoundary } from 'solid-js';
import { Router, Route } from '@solidjs/router';
import Home from './components/Home';
import About from './components/About';
function App() {
const [error, setError] = createSignal(null);
return (
<ErrorBoundary fallback={<p>Something went wrong: {error()?.message}</p>}>
<Suspense fallback={<p>Loading...</p>}>
<Router>
<Route path="/"> <Home/> </Route>
<Route path="/about"> <About/> </Route>
</Router>
</Suspense>
</ErrorBoundary>
);
}
export default App;
קומפוננטת <ErrorBoundary> תופסת כל שגיאה המתרחשת בתוך ילדיה. המאפיין fallback מציין את הקומפוננטה שיש לרנדר כאשר מתרחשת שגיאה. במקרה זה, הוא מציג פסקה עם הודעת השגיאה.
קומפוננטת <Suspense> מטפלת בהבטחות (promises) ממתינות, ובדרך כלל משמשת עם קומפוננטות אסינכרוניות או בטעינת נתונים. היא מציגה את המאפיין `fallback` עד שההבטחות מסתיימות.
כדי לגרום לשגיאה, ניתן לזרוק חריגה (exception) בתוך קומפוננטה:
function Home() {
throw new Error('Failed to load home page');
return <h1>Home</h1>;
}
export default Home;
כאשר קוד זה יתבצע, קומפוננטת <ErrorBoundary> תתפוס את השגיאה ותרנדר את קומפוננטת ה-fallback.
שיקולים בינלאומיים: בעת הצגת הודעות שגיאה, קחו בחשבון בינאום (i18n). השתמשו בספריית תרגום כדי לספק הודעות שגיאה בשפה המועדפת על המשתמש. לדוגמה, אם משתמש ביפן נתקל בשגיאה, הוא אמור לראות את הודעת השגיאה ביפנית, לא באנגלית.
שיטות עבודה מומלצות לשימוש ב-Solid Router
- שמרו על הנתיבים מאורגנים: השתמשו בנתיבים מקוננים כדי לארגן את היישום שלכם לחלקים לוגיים. זה יקל על תחזוקת הקוד והניווט בו.
- השתמשו בפרמטרים של נתיב לתוכן דינמי: השתמשו בפרמטרים של נתיב כדי ליצור כתובות URL דינמיות להצגת תוכן המבוסס על מזהה או slug ספציפי.
- טענו נתונים באופן אסינכרוני: טענו נתונים באופן אסינכרוני לפני רינדור נתיב כדי לספק חווית משתמש חלקה.
- הוסיפו מעברים בין נתיבים: השתמשו במעברים כדי לשפר את חווית המשתמש ולגרום ליישום שלכם להרגיש מלוטש יותר.
- טפלו בשגיאות באלגנטיות: הטמיעו טיפול בשגיאות כדי לתפוס ולהציג שגיאות בצורה ידידותית למשתמש.
- השתמשו בשמות נתיבים תיאוריים: בחרו שמות נתיבים המשקפים במדויק את תוכן הנתיב. זה יקל על הבנת מבנה היישום שלכם.
- בדקו את הנתיבים שלכם: כתבו בדיקות יחידה (unit tests) כדי להבטיח שהנתיבים שלכם פועלים כראוי. זה יעזור לכם לתפוס שגיאות מוקדם ולמנוע רגרסיות.
סיכום
Solid Router הוא ראוטר צד-לקוח חזק וגמיש המשתלב באופן חלק עם SolidJS. על ידי שליטה בתכונותיו וביצוע שיטות עבודה מומלצות, תוכלו לבנות יישומי עמוד-יחיד מורכבים ודינמיים המספקים חווית משתמש חלקה ומרתקת. החל מהגדרה בסיסית ועד לטכניקות מתקדמות כמו ניתוב דינמי, טעינת נתונים ומעברים, מדריך זה סיפק לכם את הידע והכישורים לנווט בביטחון בעולם הניווט צד-לקוח ב-SolidJS. אמצו את העוצמה של Solid Router וגלו את הפוטנציאל המלא של יישומי ה-SolidJS שלכם!
זכרו לעיין בתיעוד הרשמי של Solid Router לקבלת המידע והדוגמאות העדכניים ביותר: [קישור לתיעוד של Solid Router - ממלא מקום]
המשיכו לבנות דברים מדהימים עם SolidJS!